package com.gengzp.common.document.core.impl;

import com.gengzp.common.document.annotations.ApiOperation;
import com.gengzp.common.document.core.DocumentAnnotationReader;
import com.gengzp.common.document.core.DocumentCoreFunc;
import com.gengzp.common.document.core.DocumentService;
import com.gengzp.common.document.model.dto.FieldDocumentDto;
import com.gengzp.common.document.model.dto.MethodDocumentDto;
import com.gengzp.common.document.model.resp.ControllerDocumentResp;
import com.gengzp.common.document.model.resp.MethodDocumentResp;
import com.gengzp.common.document.model.resp.ParamDocumentResp;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName DocumentServiceImpl
 * @Description 接口文档服务层实现
 * @Author gengzp
 * @Date 2025/5/21 1:50
 */
@Component
public class DocumentServiceImpl implements DocumentService {

    @Autowired
    private DocumentAnnotationReader documentAnnotationReader;

    @Override
    public List<ControllerDocumentResp> searchControllerDocument() {
        List<Object> controllerBeans = documentAnnotationReader.searchAllControllerClass();
        if (controllerBeans == null || controllerBeans.isEmpty()) {
            return Collections.emptyList();
        }

        // 组装最终的返回结果
        return controllerBeans.stream().map(DocumentCoreFunc::buildControllerDocumentByBean)
                .collect(Collectors.toList());
    }

    @Override
    public MethodDocumentResp searchMethodDocument(String controllerUrl) {
        MethodDocumentResp result = new MethodDocumentResp();
        result.setMethodDocuments(new ArrayList<>());

        List<Object> controllerBeans = documentAnnotationReader.searchAllControllerClass();
        if (controllerBeans == null || controllerBeans.isEmpty()) {
            return result;
        }
        // 过滤出要查询的控制器 bean 对象
        controllerBeans = controllerBeans.stream()
                .filter(v -> controllerUrl.equals(v.getClass().getAnnotation(RequestMapping.class).value()[0])).toList();
        if (controllerBeans.isEmpty()) {
            return result;
        }

        // 控制器 bean 对象
        Object controllerBean = controllerBeans.get(0);

        // 赋值controller层的接口文档数据
        result.setControllerDocumentResp(DocumentCoreFunc.buildControllerDocumentByBean(controllerBean));

        // 根据 url 取出 controller 中方法信息
        for (Method method : controllerBean.getClass().getDeclaredMethods()) {
            MethodDocumentDto dto = new MethodDocumentDto();
            dto.setMethodUrl(documentAnnotationReader.getMappingAnnotationUrlFromMethod(method));
            dto.setMethodRequestType(documentAnnotationReader.getMethodRequestType(method));
            // 从 @ApiOperation 中取出方法描述
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            if (apiOperation != null) {
                dto.setMethodDescription(apiOperation.value());
            }
            result.getMethodDocuments().add(dto);
        }

        return result;
    }

    @Override
    public List<ParamDocumentResp> searchParamDocument(String controllerUrl, String methodUrl) {
        List<ParamDocumentResp> result = new ArrayList<>();

        // 根据完整url查询方法
        Method method = documentAnnotationReader.getMethodByUrl(controllerUrl, methodUrl);
        if (method == null) {
            return result;
        }

        // 需要输出文档的泛型类型
        Set<Class<?>> needHandleGenericTypes = new HashSet<>();

        // 先组装返回对象
        ParamDocumentResp returnParamDocument = new ParamDocumentResp();
        returnParamDocument.setParamType(DocumentCoreFunc.captureFileName(method.getReturnType().getTypeName()));
        returnParamDocument.setParamDescription(documentAnnotationReader.getParamDescription(method.getReturnType()));
        returnParamDocument.setFields(DocumentCoreFunc.getFieldDocumentFromBean(method.getReturnType(), needHandleGenericTypes));

        // 处理返回类型中的 data, 拼接泛型
        for (FieldDocumentDto field : returnParamDocument.getFields()) {
            if (StringUtils.equals(field.getFieldName(), "data")) {
                String dataFieldType = null;
                ResolvableType returnType = ResolvableType.forMethodReturnType(method).getGeneric(0);
                while (returnType.getRawClass() != null) {
                    Class<?> rawClass = returnType.getRawClass();
                    String fieldName = DocumentCoreFunc.captureFileName(rawClass.getTypeName());
                    if (StringUtils.isBlank(dataFieldType)) {
                        dataFieldType = fieldName;
                    } else if (!dataFieldType.endsWith(">")) {
                        dataFieldType = String.format("%s<%s>", dataFieldType, fieldName);
                    } else {
                        // 在计算出的位置插入新字符串
                        dataFieldType = new StringBuilder(dataFieldType).insert(dataFieldType.length() - 1, String.format("<%s>", fieldName)).toString();
                    }
                    returnType = returnType.getGeneric(0);
                }
                field.setFieldType(dataFieldType);
            }
        }

        // 处理返回类型中的泛型
        for (FieldDocumentDto fieldDocumentDto : returnParamDocument.getFields()) {
            if (!DocumentCoreFunc.checkFieldTypeNameIsJdkDataType(fieldDocumentDto.getFieldType())) {
                ResolvableType returnType = ResolvableType.forMethodReturnType(method).getGeneric(0);

                // 循环取出所有层级的泛型
                while (returnType.getRawClass() != null) {
                    needHandleGenericTypes.add(returnType.getRawClass());
                    returnType = returnType.getGeneric(0);
                }
            }
        }

        result.add(returnParamDocument);

        // 组装参数对象
        ParamDocumentResp paramDocument = new ParamDocumentResp();
        paramDocument.setParamType(DocumentCoreFunc.captureFileName(method.getParameterTypes()[0].getTypeName()));
        paramDocument.setParamDescription(documentAnnotationReader.getParamDescription(method.getParameterTypes()[0]));
        paramDocument.setFields(DocumentCoreFunc.getFieldDocumentFromBean(method.getParameterTypes()[0], needHandleGenericTypes));
        result.add(paramDocument);

        // 已经输出文档的泛型类型
        Set<Class<?>> hasHandledGenericTypes = new HashSet<>();

        // 循环组装泛型信息
        List<ParamDocumentResp> genericParamDocumentList = new ArrayList<>();
        while (!needHandleGenericTypes.equals(hasHandledGenericTypes)) {
            Set<Class<?>> newGenericTypes = new HashSet<>();
            for (Class<?> needHandleGenericType : needHandleGenericTypes) {
                if (hasHandledGenericTypes.contains(needHandleGenericType)) {
                    continue;
                }
                ParamDocumentResp genericParamDocumentResp = new ParamDocumentResp();
                genericParamDocumentResp.setParamType(DocumentCoreFunc.captureFileName(needHandleGenericType.getTypeName()));
                genericParamDocumentResp.setParamDescription(documentAnnotationReader.getParamDescription(needHandleGenericType));
                genericParamDocumentResp.setFields(DocumentCoreFunc.getFieldDocumentFromBean(needHandleGenericType, newGenericTypes));
                genericParamDocumentList.add(genericParamDocumentResp);
                hasHandledGenericTypes.add(needHandleGenericType);
            }
            needHandleGenericTypes.addAll(newGenericTypes);
        }
        result.addAll(genericParamDocumentList);

        return result;
    }

}
